package nsu.edu.zsq.service.impl.sys;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;

import lombok.extern.slf4j.Slf4j;
import nsu.edu.zsq.bean.SchClass;
import nsu.edu.zsq.bean.SchClassExample;
import nsu.edu.zsq.bean.SchMajor;
import nsu.edu.zsq.bean.SchMajorExample;
import nsu.edu.zsq.bean.Status;
import nsu.edu.zsq.bean.StuCourse;
import nsu.edu.zsq.bean.Student;
import nsu.edu.zsq.bean.StudentExample;
import nsu.edu.zsq.common.RequestHolder;
import nsu.edu.zsq.dao.SchClassMapper;
import nsu.edu.zsq.dao.SchMajorMapper;
import nsu.edu.zsq.dao.StatusMapper;
import nsu.edu.zsq.dao.StuCourseMapper;
import nsu.edu.zsq.dao.StudentMapper;
import nsu.edu.zsq.exception.ParamException;
import nsu.edu.zsq.param.ClassWithStudent;
import nsu.edu.zsq.param.PageQuery;
import nsu.edu.zsq.service.sys.SchClassService;
import nsu.edu.zsq.service.sys.StudentService;
import nsu.edu.zsq.service.sys.SysLogService;
import nsu.edu.zsq.util.BeanValidator;
import nsu.edu.zsq.util.ExcelUtil;
import nsu.edu.zsq.util.TransformMajorNoUtil;

/** 
* Description: 学校班级的service实现类<br>
*/
@Slf4j
@Service
public class SchClassServiceImpl implements SchClassService {
    
    @Autowired
    private SchClassMapper schClassMapper;
    @Autowired
    private SchMajorMapper schMajorMapper;
    @Autowired
    private SysLogService sysLogService;
    @Autowired
    private StudentService studentService;
    @Autowired
    private StudentMapper studentMapper;
    @Autowired
    private StatusMapper statusMapper;
    @Autowired
    private StuCourseMapper stuCourseMapper;
    

    @Override
    public SchClass getSchClass(int id) {
        SchClass schClass = schClassMapper.selectByPrimaryKey(id);
        return schClass;
    }

    @Override
    public PageInfo<SchClass> listSchClassWithPageByMajorNo(String majorNo, PageQuery pageQuery) {
        // 所有班级
        String allSchClass = "0";
        PageHelper.startPage(pageQuery.getPageNum(),pageQuery.getPageSize());
        SchClassExample example = new SchClassExample();
        // 根据排序号，降序
        example.setOrderByClause("sort desc");
        List<SchClass> listSchClass = null;
        if (allSchClass.equals(majorNo)) {
            listSchClass = schClassMapper.selectByExample(example);
        } else {
            example.createCriteria().andMajorNoEqualTo(majorNo);
            listSchClass = schClassMapper.selectByExample(example);
        }
        PageInfo<SchClass> pageInfo = new PageInfo<SchClass>(listSchClass, pageQuery.getNavigatePages());
        return pageInfo;
    }    

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void saveBatchSchClass(List<SchClass> listSchClass) {
        // 自定义日志内容
        List<SchClass> after = new ArrayList<SchClass>();
        for (SchClass schClass : listSchClass) {
            // 参数校验
            BeanValidator.check(schClass);
            if (checkClassNameExist(schClass.getClassName())) {
                throw new ParamException("存在相同的班级名称");
            }
            SchClass newSchClass = new SchClass();
            BeanUtils.copyProperties(schClass, newSchClass);
            after.add(newSchClass);
            
			/*
			 * schClass.setOperator(RequestHolder.getCurrentSysUser().getAccount());
			 * schClass.setOperatorTime(new Date());
			 */
            schClassMapper.insertSelective(schClass);
        }

		/*
		 * // 添加日志 String instruction = "行政班级-批量导入";
		 * sysLogService.saveSysLogBySysUser(null, after, instruction);
		 */
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void saveSchClass(SchClass schClass) {
        BeanValidator.check(schClass);
        SchClass after = new SchClass();
        BeanUtils.copyProperties(schClass, after);
        if (checkClassNameExist(schClass.getClassName())) {
            throw new ParamException("存在相同的班级名称");
        }
        SchMajorExample example = new SchMajorExample();
        example.createCriteria().andMajorNoEqualTo(schClass.getMajorNo());
        List<SchMajor> schMajor = schMajorMapper.selectByExample(example);
        // 添加院系id
        schClass.setOrgId(schMajor.get(0).getOrgId());
		/*
		 * schClass.setOperator(RequestHolder.getCurrentSysUser().getAccount());
		 * schClass.setOperatorTime(new Date());
		 */
        schClassMapper.insertSelective(schClass);
        
		/*
		 * // 添加日志 String instruction = "行政班级-添加班级";
		 * sysLogService.saveSysLogBySysUser(null, after, instruction);
		 */
    }
    
    /**
     * 坚持班级名称是否已经存在
     * @param className 班级名称
     * @return boolean true：存在 false：不存在
     */
    private boolean checkClassNameExist(String className) {
        SchClassExample example = new SchClassExample();
        example.createCriteria().andClassNameEqualTo(className);
        return schClassMapper.countByExample(example) > 0;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void deleteBatchSchClass(int[] ids) {
        List<SchClass> before = new ArrayList<SchClass>();
        for (int classId : ids) {
            SchClass schClass = getSchClass(classId);
            before.add(schClass);
            if (checkStudentExist(classId)) {
                throw new ParamException("所选班级存在学生，不能删除");
            }
            schClassMapper.deleteByPrimaryKey(classId);
        }

		/*
		 * // 添加日志 String instruction = "行政班级-批量删除";
		 * sysLogService.saveSysLogBySysUser(before, null, instruction);
		 */
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void deleteSchClass(int id) {
        SchClass before = getSchClass(id);
        if (checkStudentExist(id)) {
            throw new ParamException("该班级存在学生，不能删除");
        }
        schClassMapper.deleteByPrimaryKey(id);
        
		/*
		 * // 添加日志 String instruction = "行政班级-单个删除";
		 * sysLogService.saveSysLogBySysUser(before, null, instruction);
		 */
    }

    /**
     * 根据班级id检查该班级下是否存在学生
     * @param classId 班级id
     * @return boolean true：存在 false：不存在
     */
    private boolean checkStudentExist(int classId) {
        StudentExample example = new StudentExample();
        example.createCriteria().andClassIdEqualTo(classId);
        return studentMapper.countByExample(example) > 0;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void updateSchClass(SchClass schClass) {
        SchClass oldSchClass = getSchClass(schClass.getId());
        if (!oldSchClass.getClassName().equals(schClass.getClassName())) {
            if (checkClassNameExist(schClass.getClassName())) {
                throw new ParamException("存在相同的班级名称");
            }
        }
        SchClass before = new SchClass();
        before.setId(oldSchClass.getId());
        before.setClassName(oldSchClass.getClassName());
        before.setSort(oldSchClass.getSort());
		/*
		 * before.setOperator(oldSchClass.getOperator());
		 * before.setOperatorTime(oldSchClass.getOperatorTime());
		 * 
		 * schClass.setOperator(RequestHolder.getCurrentSysUser().getAccount());
		 * schClass.setOperatorTime(new Date());
		 */
        schClassMapper.updateByPrimaryKeySelective(schClass);
        
		/*
		 * // 添加日志 String instruction = "行政班级-编辑";
		 * sysLogService.saveSysLogBySysUser(before, schClass, instruction);
		 */
    }

    @Override
    public PageInfo<Student> listStudentByMajorNoWithPage(String majorNo, PageQuery pageQuery) {
        if (majorNo == null || majorNo.length() < 0) {
            throw new ParamException("majorNo不能为空");
        }
        PageHelper.startPage(pageQuery.getPageNum(),pageQuery.getPageSize());
        StudentExample example = new StudentExample();
        // 0:代表学生没有班级
        example.createCriteria().andMajorNoEqualTo(majorNo).andClassIdEqualTo(0).andIsDeleteNotEqualTo(1);
        List<Student> listStudent = studentMapper.selectByExample(example);
        // 将学生的专业代码转换为专业名称
        try {
            TransformMajorNoUtil.transformMajor(listStudent);
        } catch (Exception e) {
            e.printStackTrace();
        }
        PageInfo<Student> pageInfo = new PageInfo<Student>(listStudent, pageQuery.getNavigatePages());
        return pageInfo;
    }

    @Override
    public PageInfo<Student> listStudentByClassIdWithPage(int classId, PageQuery pageQuery) {
        PageHelper.startPage(pageQuery.getPageNum(),pageQuery.getPageSize());
        StudentExample example = new StudentExample();
        example.createCriteria().andClassIdEqualTo(classId).andIsDeleteNotEqualTo(1);;
        List<Student> listStudent = studentMapper.selectByExample(example);
        // 将学生的专业代码转换为专业名称
        try {
            TransformMajorNoUtil.transformMajor(listStudent);
        } catch (Exception e) {
            e.printStackTrace();
        }
        PageInfo<Student> pageInfo = new PageInfo<Student>(listStudent, pageQuery.getNavigatePages());
        return pageInfo;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void addStuToClass(int stuId, int classId) {
        Student student = studentService.getStudent(stuId);
        Student before = Student.builder().stuId(stuId).classId(student.getClassId())
                .operator(student.getOperator()).operatorTime(student.getOperatorTime()).build();
        Student after = Student.builder().stuId(stuId).classId(classId)
                .operator(RequestHolder.getCurrentSysUser().getAccount())
                .operatorTime(new Date()).build();
        studentMapper.updateByPrimaryKeySelective(after);
        updateSchClassStuNumber(classId);
		/*
		 * // 添加日志 String instruction = "行政班级-班级管理-单个添加学生";
		 * sysLogService.saveSysLogBySysUser(before, after, instruction);
		 */
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void addBatchStuToClass(int[] stuIds, int classId) {
        List<Student> before = new ArrayList<Student>();
        List<Student> after = new ArrayList<Student>();
        for (int stuId : stuIds) {
            Student student = studentService.getStudent(stuId);
            Student beforeStudent = Student.builder().stuId(stuId).classId(student.getClassId())
                    .operator(student.getOperator()).operatorTime(student.getOperatorTime()).build();
            before.add(beforeStudent);
            Student afterStudent = Student.builder().stuId(stuId).classId(classId)
                    .operator(RequestHolder.getCurrentSysUser().getAccount())
                    .operatorTime(new Date()).build();
            after.add(afterStudent);
            studentMapper.updateByPrimaryKeySelective(afterStudent);
        }
        updateSchClassStuNumber(classId);
		/*
		 * // 添加日志 String instruction = "行政班级-班级管理-批量添加学生";
		 * sysLogService.saveSysLogBySysUser(before, after, instruction);
		 */
    }
    
    /**
     * 更新班级人数
     * @param classId 班级id
     */
    @Transactional(rollbackFor = Exception.class)
    private void updateSchClassStuNumber(int classId) {
        // 通过班级id获取该班级学生人数
        StudentExample example = new StudentExample();
        example.createCriteria().andClassIdEqualTo(classId);
        long countStudentByClassId = studentMapper.countByExample(example);
        // 更新班级人数到该班级
        SchClass schClass = new SchClass();
        schClass.setId(classId);
        schClass.setStuNumber((int)countStudentByClassId);
        schClassMapper.updateByPrimaryKeySelective(schClass);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void deleteStuFromClass(int stuId) {
        Student student = studentService.getStudent(stuId);
        Student before = Student.builder().stuId(stuId).classId(student.getClassId())
                .operator(student.getOperator()).operatorTime(student.getOperatorTime()).build();
        Student after = Student.builder().stuId(stuId).classId(0)
                .operator(RequestHolder.getCurrentSysUser().getAccount())
                .operatorTime(new Date()).build();
        studentMapper.updateByPrimaryKeySelective(after);
        updateSchClassStuNumber(student.getClassId());
		/*
		 * // 添加日志 String instruction = "行政班级-班级管理-单个移除学生";
		 * sysLogService.saveSysLogBySysUser(before, after, instruction);
		 */
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void deleteBatchFromClass(int[] stuIds) {
        List<Student> before = new ArrayList<Student>();
        List<Student> after = new ArrayList<Student>();
        int classId = 0;
        for (int stuId : stuIds) {
            Student student = studentService.getStudent(stuId);
            classId = student.getClassId();
            Student beforeStudent = Student.builder().stuId(stuId).classId(student.getClassId())
                    .operator(student.getOperator()).operatorTime(student.getOperatorTime()).build();
            before.add(beforeStudent);
            Student afterStudent = Student.builder().stuId(stuId).classId(0)
                    .operator(RequestHolder.getCurrentSysUser().getAccount())
                    .operatorTime(new Date()).build();
            after.add(afterStudent);
            studentMapper.updateByPrimaryKeySelective(afterStudent);
        }
        updateSchClassStuNumber(classId);
		/*
		 * // 添加日志 String instruction = "行政班级-班级管理-批量移除学生";
		 * sysLogService.saveSysLogBySysUser(before, after, instruction);
		 */
        
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void importSchClassFromExcel(MultipartFile excelFile) {
        List<SchClass> listSchClass = ExcelUtil.importExcel(excelFile, 1, 1, SchClass.class);
        saveBatchSchClass(listSchClass);
        log.info("导入学校班级数据一共【{}】条",listSchClass.size());
    }

    @Override
    public void exportSchClassToExcel(HttpServletResponse response) {
        SchClassExample example = new SchClassExample();
        List<SchClass> listSchClass = schClassMapper.selectByExample(example);
        // 导出操作
        ExcelUtil.exportExcel(listSchClass,"班级列表","Sheet1",SchClass.class,"学校班级.xlsx",response);
    }
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void exportStuToClass(MultipartFile excelFile) {
        List<ClassWithStudent> listClassWithStudent = ExcelUtil.importExcel(excelFile, 1, 1, ClassWithStudent.class);
        List<Student> before = new ArrayList<Student>();
        List<Student> after = new ArrayList<Student>();
        for (ClassWithStudent classWithStudent : listClassWithStudent) {
            if (checkClassExist(classWithStudent.getStuNo())) {
                throw new ParamException("学生已经拥有班级");
            }
            Student beforeStudent = Student.builder().stuNo(classWithStudent.getStuNo()).classId(0).build();
            before.add(beforeStudent);
            Student afterStudent = Student.builder().stuNo(classWithStudent.getStuNo()).classId(classWithStudent.getClassId())
                    .operator(RequestHolder.getCurrentSysUser().getAccount())
                    .operatorTime(new Date()).build();
            StudentExample example = new StudentExample();
            example.createCriteria().andStuNoEqualTo(classWithStudent.getStuNo());
            studentMapper.updateByExampleSelective(afterStudent, example);
            updateSchClassStuNumber(classWithStudent.getClassId());
            // 减轻日志内容长度
			/*
			 * afterStudent.setOperator(null); afterStudent.setOperatorTime(null);
			 */
            after.add(afterStudent);
        }
		/*
		 * // 添加日志 String instruction = "行政班级-班级管理-导入学生";
		 * sysLogService.saveSysLogBySysUser(before, after, instruction);
		 * log.info("导入学生和班级关联数据一共【{}】条",listClassWithStudent.size());
		 */
        
    }
    
    /**
     * 根据学号检查该学生是否拥有班级
     * @param stuNo 学号
     * @return boolean true：拥有 false：不拥有
     */
    private boolean checkClassExist(String stuNo) {
        StudentExample example = new StudentExample();
        example.createCriteria().andStuNoEqualTo(stuNo).andClassIdNotEqualTo(0);
        return studentMapper.countByExample(example) > 0;
    }

    @Override
    public PageInfo<SchClass> listTeachClassWithPage(String majorNo, int courseType, PageQuery pageQuery) {
        List<SchClass> listSchClass = null;
        PageHelper.startPage(pageQuery.getPageNum(),pageQuery.getPageSize());
        if (courseType == 3) {
            // 选课
            listSchClass = schClassMapper.listPublicTeachClass();
        } else if (courseType == 2) {
            // 专业选修课
            listSchClass = schClassMapper.listTeachClassByMajorNo(majorNo);
        }
        PageInfo<SchClass> pageInfo = new PageInfo<SchClass>(listSchClass, pageQuery.getNavigatePages());
        return pageInfo;
    }

    @Override
    public int chooseCourseState() {
        Status status = statusMapper.selectByPrimaryKey(1);
        return status.getState();
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void updateStatus(Status status) {
        status.setId(1);
        statusMapper.updateByPrimaryKeySelective(status);
    }

    @Override
    public PageInfo<Student> listTeachClassStudent(int tchCourseId, PageQuery pageQuery) {
        PageHelper.startPage(pageQuery.getPageNum(),pageQuery.getPageSize());
        List<Student> listStudent = studentMapper.listTeachClassStudent(tchCourseId);
        PageInfo<Student> pageInfo = new PageInfo<Student>(listStudent, pageQuery.getNavigatePages());
        return pageInfo;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void delStuCourse(int[] stuCourseIds) {
        List<StuCourse> before = new ArrayList<StuCourse>();
        for (int stuCourseId : stuCourseIds) {
            StuCourse beforeStuCourse = stuCourseMapper.selectByPrimaryKey(stuCourseId);
            before.add(beforeStuCourse);
            stuCourseMapper.deleteByPrimaryKey(stuCourseId);
        }
        
		/*
		 * // 添加日志 String instruction = "教学班级-删除学生";
		 * sysLogService.saveSysLogBySysUser(before, null, instruction);
		 */
    }

}
